<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>多个矩形</title>
  <style>
    body {
      margin: 0;
    }

    canvas {
      width: 100vw;
      height: 100vh;
      display: block;
    }
  </style>

</head>

<body>
  <canvas id="c"></canvas>
</body>
<!-- vertex shader -->
<script id="vertex-shader-2d" type="x-shader/x-vertex">
  attribute vec2 a_position;
  uniform vec2 u_resolution;

  void main() {
    // convert the rectangle from the pixels 0.0 to 1.0
    vec2 zeroToOne = a_position / u_resolution;

    // covert from 0->1 to 0->2
    vec2 zeroToTwo = zeroToOne * 2.0;

    // convert from 0->2 to -1 -> +1(clipsace)
    vec2 clipSpace = zeroToTwo - 1.0;

    gl_Position = vec4(clipSpace * vec2(1,-1), 0, 1);
  }
 </script>
<!-- fragment shader -->
<script id="fragment-shader-2d" type="x-shader/x-fragment">
  precision mediump float;

  uniform vec4 u_color;

  void main() {
    gl_FragColor = u_color;
  }
</script>
<script src="./lib/webgl-utils.js"></script>
<script>

  "use strict";

  function createShaderFromScript(gl, shaderScriptId) {
    var shaderScript = document.getElementById(shaderScriptId);
    var shaderSource = document.getElementById(shaderScriptId).text;
    var shaderType;
    if (shaderScript.type === 'x-shader/x-vertex') {
      shaderType = gl.VERTEX_SHADER;
    }
    if (shaderScript.type === 'x-shader/x-fragment') {
      shaderType = gl.FRAGMENT_SHADER;
    }
    var shader = gl.createShader(shaderType);
    gl.shaderSource(shader, shaderSource);
    gl.compileShader(shader);

    var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);

    if (success) {
      return shader;
    }
    console.log(gl.getShaderInfoLog(shader))
    gl.deleteShader(shader);
  }

  function createProgram(gl, shaders) {
    var program = gl.createProgram();
    shaders.forEach(function (shader) {
      gl.attachShader(program, shader);
    });
    gl.linkProgram(program);

    var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
    if (linked) {
      return program;
    }
    console.log(gl.getProgramInfoLog(program));
    gl.deleteProgram(program);
  }

  function createProgramFromScripts(gl, shaderScriptIds) {
    const shaders = [];
    for (let ii = 0; ii < shaderScriptIds.length; ++ii) {
      shaders.push(createShaderFromScript(gl, shaderScriptIds[ii]))
    }
    return createProgram(gl, shaders);
  }

  function resizeCanvasToDisplaySize(canvas, multiplier) {
    multiplier = multiplier || 1;
    const width = canvas.clientWidth * multiplier | 0;
    const height = canvas.clientHeight * multiplier | 0;
    if (canvas.width !== width || canvas.height !== height) {
      canvas.width = width;
      canvas.height = height;
      return true;
    }
    return false;
  }


  function main() {
    const canvas = document.getElementById('c');
    const gl = canvas.getContext('webgl');
    if (!gl) {
      return;
    }

    // setup GLSL program
    var program = createProgramFromScripts(gl, ['vertex-shader-2d', 'fragment-shader-2d']);

    // Look up where the vertex data needs to go
    var positionAttributeLocation = gl.getAttribLocation(program, 'a_position');

    // Look up uniform loactions

    var resolutionUniformLocation = gl.getUniformLocation(program, 'u_resolution');
    var colorUniformLocation = gl.getUniformLocation(program, 'u_color');

    // Create a buffer to put three 2d clip space points in 
    var positionBuffer = gl.createBuffer();

    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

    resizeCanvasToDisplaySize(gl.canvas);

    // Tell WebGL how to convert from clip space to pixels
    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

    // Clear canvas

    gl.clearColor(0, 0, 0, 0);
    gl.clear(gl.COLOR_BUFFER_BIT);

    // Tell it to use our program (pair of shaders)
    gl.useProgram(program);

    // Turn on the attribute

    gl.enableVertexAttribArray(positionAttributeLocation);

    // Bind the position buffer
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

    // Tell attribute how to get data out of positionBuffer (ARRAY_BUFFER)
    var size = 2;  // 2 components per iteration
    var type = gl.FLOAT; // the data is 32bit floats
    var normalize = false; // dont normalize data
    var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
    var offset = 0; // start at the beginning of the buffer

    gl.vertexAttribPointer(positionAttributeLocation, size, type, normalize, stride, offset);

    // set the resolution
    gl.uniform2f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height);


    // draw 50 random rectangles in random colors
    for (var ii = 0; ii < 50, ++ii;) {
      // Setup random rectangle
      // This will write to positionBuffer because
      // its the last thing we bound on the ARRAY_BUFFER
      // bind point

      setRectangle(gl, randomInt(300), randomInt(300), randomInt(300), randomInt(300));

      // Set a random color
      gl.uniform4f(colorUniformLocation, Math.random, Math.random(), Math.random(), 1);

      // Draw the rectangle
      var primitiveType = gl.TRIANGLES;
      var offset = 0;
      var count = 6;
      gl.drawArrays(primitiveType, offset, count);
    }

    // Return a random interger from 0 to range -1
    function randomInt(range) {
      return Math.floor(Math.random * range);
    }

    // Fill the buffer with the values that define a rectangle
    function setRectangle(gl, x, y, width, height) {
      var x1 = x;
      var x2 = x1 + width;
      var y1 = y;
      var y2 = y + height;
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        x1, y1,
        x2, y1,
        x1, y2,
        x1, y2,
        x2, y1,
        x2, y2,
      ]), gl.STATIC_DRAW);
    }
  }

  document.addEventListener('DOMContentLoaded', main);

</script>

</html>